﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Citrix.Cmp;
using System.ComponentModel;
using Citrix.XaAdminMobile.Model;
using System.Windows;
using Citrix.XenApp.Commands;
using Citrix.XaAdminMobile.Util;

namespace Citrix.XaAdminMobile.ViewModel
{
    /// <summary>
    /// The v-m object for displaying a single XenApp server.
    /// </summary>
    internal class ServerViewModel : INotifyPropertyChanged, IPage
    {
        /// <summary>
        /// The max (100%) load value.
        /// </summary>
        private const double MaxLoad = 10000;

        /// <summary>
        /// The associated model object.
        /// </summary>
        private readonly IServerModel model;

        /// <summary>
        /// A reference back to the root v-m object.
        /// </summary>
        private readonly ViewModelManager vmRoot;

        /// <summary>
        /// Set as the [0..100]* proportional height of the unused space above the server load
        /// bar.
        /// </summary>
        private GridLength loadUnusedHeight;

        /// <summary>
        /// Set as the [0..100]* proportional height of the bar to show the server load.
        /// </summary>
        private GridLength loadUsedHeight;

        /// <summary>
        /// Initialisation ctor.
        /// </summary>
        /// <param name="vmMgr">The root v-m object.</param>
        /// <param name="source">The source model object.</param>
        /// <exception cref="ArgumentNullException">Thrown if any argument is null.</exception>
        internal ServerViewModel(ViewModelManager vmMgr, IServerModel source)
        {
            if (null == vmMgr)
            {
                throw new ArgumentNullException("vmMgr");
            }
            if (null == source)
            {
                throw new ArgumentNullException("source");
            }

            this.vmRoot = vmMgr;
            this.model = source;
            this.model.PropertyChanged += new PropertyChangedEventHandler(Model_PropertyChanged);
            this.DisplayServerDetailsCommand = new DelegateCommand(() =>
            {
                this.vmRoot.NavigateToPage(this);
            });
            RefreshLoad();
        }

        /// <summary>
        /// The back command. Used in the phone layout to navigate back to the list of servers.
        /// </summary>
        public DelegateCommand BackCommand
        {
            get { return this.vmRoot.DefaultBackCommand; }
        }

        /// <summary>
        /// Used on the server list view to trigger the display of the details of this server.
        /// </summary>
        public DelegateCommand DisplayServerDetailsCommand
        {
            get;
            private set;
        }

        /// <summary>
        /// The date/time the Citrix server was installed.
        /// </summary>
        public string CitrixInstallDate
        {
            get
            {
                var date = this.model.CitrixInstallDate;
                if (date.HasValue)
                {
                    return date.ToString();
                }
                return null;
            }
        }

        /// <summary>
        /// The install path of the Citrix server.
        /// </summary>
        public string CitrixInstallPath
        {
            get
            {
                return this.model.CitrixInstallPath;
            }
        }

        /// <summary>
        /// The Citrix product edition.
        /// </summary>
        public string CitrixProductEdition
        {
            get
            {
                var edition = this.model.CitrixProductEdition;
                if (edition.HasValue)
                {
                    return edition.Value.ToString();
                }
                else
                {
                    return Properties.Resources.ProductEditionUnknownLabel;
                }
            }
        }

        /// <summary>
        /// The product name of the Citrix (Metaframe/PS/XenApp) server.
        /// </summary>
        public string CitrixProductName
        {
            get
            {
                return this.model.CitrixProductName;
            }
        }

        /// <summary>
        /// The service pack (if any) applied to the Citrix server.
        /// </summary>
        public string CitrixServicePack
        {
            get
            {
                return this.model.CitrixServicePack;
            }
        }

        /// <summary>
        /// The Citrix product version.
        /// </summary>
        public string CitrixVersion
        {
            get
            {
                Version ver = this.model.CitrixVersion;
                return (null != ver) ? ver.ToString() : "0.0.0.0";
            }
        }

        /// <summary>
        /// The name of the Citrix license server that this server is using.
        /// </summary>
        public string LicenseServerName
        {
            get
            {
                return this.model.LicenseServerName;
            }
        }

        /// <summary>
        /// The port of the Citrix license server that this server is using.
        /// </summary>
        public string LicenseServerPort
        {
            get
            {
                var port = this.model.LicenseServerPort;
                if (port.HasValue && port.Value > 0)
                {
                    return port.Value.ToString();
                }
                return null;
            }
        }

        /// <summary>
        /// Returns the proportional to height to set the height of of unused portion of the
        /// load of the server.
        /// </summary>
        public GridLength LoadUnusedHeight
        {
            get { return this.loadUnusedHeight; }
        }

        /// <summary>
        /// Returns the proportional star height to set the height of the load graph.
        /// </summary>
        public GridLength LoadUsedHeight
        {
            get { return this.loadUsedHeight; }
        }

        /// <summary>
        /// The current XenApp load index.
        /// </summary>
        public uint Load
        {
            get { return this.model.Load; }
        }

        /// <summary>
        /// Whether or not logons are enabled for this server.
        /// </summary>
        public string LogonsEnabled
        {
            get
            {
                if (this.model.LogonsEnabled.HasValue)
                {
                    return this.model.LogonsEnabled.Value.ToString();
                }
                else
                {
                    return "?";
                }
            }
        }

        /// <summary>
        /// The logon mode of the server.
        /// </summary>
        public LogOnMode LogonMode
        {
            get { return this.model.LogonMode; }
        }

        /// <summary>
        /// The server name.
        /// </summary>
        public string Name
        {
            get { return this.model.Name; }
        }

        /// <summary>
        /// Returns a string that describes the bitness of the server OS.
        /// </summary>
        public string OsBitness
        {
            get
            {
                bool? is64 = this.model.Is64Bit;
                if (is64.HasValue)
                {
                    if (is64.Value)
                    {
                        return Properties.Resources.OsBitness64;
                    }
                    else
                    {
                        return Properties.Resources.OsBitness32;
                    }
                }
                else
                {
                    return Properties.Resources.OsBitnessUnknown;
                }
            }
        }

        /// <summary>
        /// The service pack applied to the operating system.
        /// </summary>
        public string OsServicePack
        {
            get
            {
                return this.model.OsServicePack;
            }
        }

        /// <summary>
        /// The version of the operating system.
        /// </summary>
        public string OsVersion
        {
            get
            {
                var version = this.model.OsVersion;
                if (null != version)
                {
                    return version.ToString();
                }
                return "0.0.0.0";
            }
        }

        /// <summary>
        /// The current power and capacity management mode.
        /// </summary>
        public string PowerCapManagementMode
        {
            get
            {
                switch (this.model.PowerCapManagementMode)
                {
                    case PcmMode.Drain:
                        {
                            return Properties.Resources.PcmDrain;
                        }
                    case PcmMode.DrainUntilRestart:
                        {
                            return Properties.Resources.PcmDrainUntilRestart;
                        }
                    case PcmMode.Normal:
                        {
                            return Properties.Resources.PcmNormal;
                        }
                    default:
                        {
                            return Properties.Resources.PcmUnknown;
                        }
                }
            }
        }

        /// <summary>
        /// The number of sessions running on the server.
        /// </summary>
        public string SessionCount
        {
            get
            {
                int? count = this.model.SessionCount;
                if (count.HasValue)
                {
                    return count.Value.ToString();
                }
                else
                {
                    return "?";
                }
            }
        }

        /// <summary>
        /// The name of the zone this server belongs to.
        /// </summary>
        public string ZoneName
        {
            get { return this.model.ZoneName; }
        }

        /// <summary>
        /// The zone election preference.
        /// </summary>
        public ZoneElectionPreference ZoneElectionPreference
        {
            get { return this.model.ZoneElectionPreference; }
        }

        /// <summary>
        /// Refreshes the load values used to draw the load graph.
        /// </summary>
        private void RefreshLoad()
        {
            double loadPercent = this.model.Load / MaxLoad;
            if (loadPercent > 1.0)
            {
                loadPercent = 1.0;
            }
            if (loadPercent < 0.0)
            {
                loadPercent = 0.0;
            }
            this.loadUsedHeight = new GridLength(loadPercent * 100, GridUnitType.Star);
            this.loadUnusedHeight = new GridLength((1 - loadPercent) * 100, GridUnitType.Star);
        }

        /// <summary>
        /// Handle changes in the underlying model object.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.vmRoot.UiDispatch(() =>
            {
                if (e.PropertyName == "CitrixInstallPath")
                {
                    OnPropertyChanged("CitrixInstallPath");
                }
                else if (e.PropertyName == "CitrixInstallDate")
                {
                    OnPropertyChanged("CitrixInstallDate");
                }
                else if (e.PropertyName == "CitrixProductEdition")
                {
                    OnPropertyChanged("CitrixProductEdition");
                }
                else if (e.PropertyName == "CitrixProductName")
                {
                    OnPropertyChanged("CitrixProductName");
                }
                else if (e.PropertyName == "CitrixServicePack")
                {
                    OnPropertyChanged("CitrixServicePack");
                }
                else if (e.PropertyName == "CitrixVersion")
                {
                    OnPropertyChanged("CitrixVersion");
                }
                else if (e.PropertyName == "Is64Bit")
                {
                    OnPropertyChanged("OsBitness");
                }
                else if (e.PropertyName == "LicenseServerName")
                {
                    OnPropertyChanged("LicenseServerName");
                }
                else if (e.PropertyName == "LicenseServerPort")
                {
                    OnPropertyChanged("LicenseServerPort");
                }
                else if (e.PropertyName == "Load")
                {
                    RefreshLoad();
                    OnPropertyChanged("Load");
                    OnPropertyChanged("LoadUnusedHeight");
                    OnPropertyChanged("LoadUsedHeight");
                }
                else if (e.PropertyName == "Name")
                {
                    OnPropertyChanged("Name");
                }
                else if (e.PropertyName == "OsServicePack")
                {
                    OnPropertyChanged("OsServicePack");
                }
                else if (e.PropertyName == "OsVersion")
                {
                    OnPropertyChanged("OsVersion");
                }
                else if (e.PropertyName == "SessionCount")
                {
                    OnPropertyChanged("SessionCount");
                }
                else if (e.PropertyName == "PowerCapManagementMode")
                {
                    OnPropertyChanged("PowerCapManagementMode");
                }
                else if (e.PropertyName == "LogonsEnabled")
                {
                    OnPropertyChanged("LogonsEnabled");
                }
                else if (e.PropertyName == "LogonMode")
                {
                    OnPropertyChanged("LogonMode");
                }
                else if (e.PropertyName == "ZoneName")
                {
                    OnPropertyChanged("ZoneName");
                }
                else if (e.PropertyName == "ZoneElectionPreference")
                {
                    OnPropertyChanged("ZoneElectionPreference");
                }
            });
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Fired whenever a public property changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Fires the property change event. Maybe called from any thread - we always fire the
        /// event on the main UI thread.
        /// </summary>
        /// <param name="propertyName">The name of the property that changed.</param>
        private void OnPropertyChanged(string propertyName)
        {
            NotifyHelper.VerifyProperty(propertyName, this);
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged.Raise(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion // INotifyPropertyChanged Members

        #region IPage members

        /// <summary>
        /// Called when this v-m is displayed/deactivated as an active page using
        /// ServerDetailsView.
        /// </summary>
        /// <param name="isActive">True when displayed, false when deactivated.</param>
        public void NotifyActiveChanged(bool isActive)
        {
            if (isActive)
            {
                this.vmRoot.ServersViewModel.NotifyServerSelected(this);
            }
        }

        /// <summary>
        /// Handler for the back button being pressed.
        /// </summary>
        public void NotifyBackButtonPressed()
        {
            this.vmRoot.DefaultBackCommand.Execute();
        }

        /// <summary>
        /// The root v-m object.
        /// </summary>
        public ViewModelManager VmManager
        {
            get { return this.vmRoot; }
        }

        #endregion
    }
}
